#include "ecv_vi_image.h"


/*
 * Gd includes
 */

#include "gd.h"
#include "gdfontt.h"
#include "gdfontl.h"
#include <stdlib.h>
#include <memory.h>

G_DEFINE_TYPE (EcvVi_Image, ecv_vi_image, ECV_TYPE_VI);

#define ECV_VI_IMAGE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ECV_TYPE_VI_IMAGE, EcvVi_ImagePrivate))

struct _EcvVi_ImagePrivate
{
  gchar * file;
  int width;
  int height;
  int bpp;
  char * data;
  int size;
  gdImagePtr im;
  int failed;
};

enum
{
  PROP_0,
  PROP_ECV_WIDTH,
  PROP_ECV_HEIGHT,
  PROP_ECV_BPP,
  PROP_ECV_FILE
};

//------------------------------------------------------
void 
image_run (EcvVi *self)
{
  g_return_if_fail (ECV_IS_VI (self));

  EcvVi_Image * image = ECV_VI_IMAGE(self);
}

//------------------------------------------------------
void 
image_step_begin (EcvVi *self)
{
  g_return_if_fail (ECV_IS_VI (self));

  EcvVi_Image * image = ECV_VI_IMAGE(self);
}

//------------------------------------------------------

void 
image_step_end (EcvVi *self)
{
  g_return_if_fail (ECV_IS_VI (self));
  
  EcvVi_Image * image = ECV_VI_IMAGE(self);
}

//------------------------------------------------------

char * 
image_get_data (EcvVi *self)
{
  g_return_if_fail (ECV_IS_VI (self));
  
  EcvVi_Image * image = ECV_VI_IMAGE(self);
  
  if (image->priv->data != NULL)
    return (image->priv->data);
  return NULL;
}

//------------------------------------------------------

int 
image_get_data_size (EcvVi *self)
{
  g_return_if_fail (ECV_IS_VI (self));
  
  EcvVi_Image * image = ECV_VI_IMAGE(self);

  if (image->priv->data != NULL)
    return (image->priv->size);
  return -1;
}

int
image_failed(EcvVi * self)
{
  g_return_if_fail (ECV_IS_VI (self));
  
  EcvVi_Image * image = ECV_VI_IMAGE(self);

  return image->priv->failed;
}

image_create (EcvVi *self)
{
  g_return_if_fail (ECV_IS_VI (self));

  EcvVi_Image * image = ECV_VI_IMAGE(self);
  
  /* ... inside a function ... */
  FILE *in;
  in = fopen(image->priv->file, "rb");
  image->priv->im = gdImageCreateFromPng(in);
  image->priv->width = gdImageSX(image->priv->im);
  image->priv->height = gdImageSY(image->priv->im);
  image->priv->data = malloc(sizeof (char)*3*image->priv->width*image->priv->height);
  int x = 0;
  int y = 0;
  int c = 0;
  printf ("width = %i, height = %i\n",image->priv->width, image->priv->height);
  int pc = 0;
  for (y;y<image->priv->height;y=y+1)
    {
      //      printf ("%i: ",y);
      x=0;
      for (x;x<image->priv->width;x=x+1)
	{
	  c = gdImageGetPixel(image->priv->im, x, y);
	  image->priv->data[pc]=c;
	  image->priv->data[pc+1]=c;
	  image->priv->data[pc+2]=c;
	  pc+=3;
	  //	  printf ("%06x ",c);
	}
      //      printf ("\n");
    }
  image->priv->size = pc;
  gdImageDestroy(image->priv->im);
  image->priv->im = NULL;
  fclose(in);
  
  /* ... Use the image ... */

}

static void
ecv_vi_image_set_property (GObject      *object,
                        guint         property_id,
                        const GValue *value,
                        GParamSpec   *pspec)
{
  EcvVi_Image *self = ECV_VI_IMAGE (object);

  switch (property_id)
    {
    case PROP_ECV_WIDTH:
      self->priv->width = g_value_get_uint (value);
      break;

    case PROP_ECV_HEIGHT:
      self->priv->height = g_value_get_uint (value);
      break;

    case PROP_ECV_BPP:
      self->priv->bpp = g_value_get_uint (value);
      break;

    case PROP_ECV_FILE:
      self->priv->file = g_strdup(g_value_get_string (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
ecv_vi_image_get_property (GObject    *object,
                        guint       property_id,
                        GValue     *value,
                        GParamSpec *pspec)
{
  EcvVi_Image *self = ECV_VI_IMAGE (object);

  switch (property_id)
    {
    case PROP_ECV_WIDTH:
      g_value_set_uint (value, self->priv->width);
      break;

    case PROP_ECV_HEIGHT:
      g_value_set_uint (value, self->priv->height);
      break;

    case PROP_ECV_BPP:
      g_value_set_uint (value, self->priv->bpp);
      break;

    case PROP_ECV_FILE:
      g_value_set_string (value, self->priv->file);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
      }
}

static void
ecv_vi_image_dispose (GObject *gobject)
{
  EcvVi_Image *self = ECV_VI_IMAGE (gobject);

  /* 
   * In dispose, you are supposed to free all types referenced from this
   * object which might themselves hold a reference to self. Generally,
   * the most simple solution is to unref all members on which you own a 
   * reference.
   */

  /* dispose might be called multiple times, so we must guard against
   * calling g_object_unref() on an invalid GObject.
   */

  /*  if (self->priv->)
    {
      g_object_unref (self->priv->an_object);
      }*/

  /* Chain up to the parent class */
  G_OBJECT_CLASS (ecv_vi_image_parent_class)->dispose (gobject);
}

static void
ecv_vi_image_finalize (GObject *gobject)
{
  EcvVi_Image *self = ECV_VI_IMAGE (gobject);

  if (self->priv->data != NULL)
    {
      free(self->priv->data);      
      self->priv->data = NULL;

    }

  //  g_free (self->a_string);

  /* Chain up to the parent class */
  G_OBJECT_CLASS (ecv_vi_image_parent_class)->finalize (gobject);
}

static GObject *
ecv_vi_image_constructor (GType                  gtype,
                       guint                  n_properties,
                       GObjectConstructParam *properties)
{
  GObject *obj;

  {
    /* Always chain up to the parent constructor */
    EcvVi_ImageClass *klass;
    GObjectClass *parent_class;  
    parent_class = G_OBJECT_CLASS (ecv_vi_image_parent_class);
    obj = parent_class->constructor (gtype, n_properties, properties);
  }
  
  /* update the object state depending on constructor properties */

  return obj;
}

static void
ecv_vi_image_class_init (EcvVi_ImageClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  GParamSpec *pspec;

  gobject_class->dispose = ecv_vi_image_dispose;
  gobject_class->finalize = ecv_vi_image_finalize;
  gobject_class->set_property = ecv_vi_image_set_property;
  gobject_class->get_property = ecv_vi_image_get_property;
pspec = g_param_spec_uint ("width",
			     "",
			     "image width",
			     1,
			     65534,
			     320,
			     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
  
  g_object_class_install_property (gobject_class,
                                   PROP_ECV_WIDTH,
                                   pspec);

  pspec = g_param_spec_uint ("height",
			     "",
			     "image height",
			     1,
			     65534,
			     240,
			     G_PARAM_READWRITE);
  g_object_class_install_property (gobject_class,
                                   PROP_ECV_HEIGHT,
                                   pspec);

  pspec = g_param_spec_uint ("bpp",
			     "",
			     "image bytes per pixel",
			     1,
			     65534,
			     24,
			     G_PARAM_READWRITE);
  g_object_class_install_property (gobject_class,
                                   PROP_ECV_BPP,
                                   pspec);

  pspec = g_param_spec_string ("file",
			       "",
			       "file name",
			       "",
			       G_PARAM_READWRITE);
  g_object_class_install_property (gobject_class,
                                   PROP_ECV_FILE,
                                   pspec);

  g_type_class_add_private (klass, sizeof (EcvVi_ImagePrivate));
  gobject_class->constructor = ecv_vi_image_constructor;

  EcvViClass *parent_class;  
  parent_class = ECV_VI_CLASS (klass);
  parent_class->create        = image_create;
  parent_class->run           = image_run;
  parent_class->step_begin    = image_step_begin;
  parent_class->step_end      = image_step_end;
  parent_class->get_data      = image_get_data;
  parent_class->get_data_size = image_get_data_size;
  parent_class->failed        = image_failed;
}

static void
ecv_vi_image_init (EcvVi_Image *self)
{
  self->priv = ECV_VI_IMAGE_GET_PRIVATE (self);
  self->priv->failed = 0;

  //  self->priv->an_object = g_object_new (ECV_TYPE_BA, NULL);
}

//------------------------------------------------------
/*                     methods                        */
//------------------------------------------------------

EcvVi_Image * 
ecv_vi_image_new (int width, int height, int bpp, char * file)
{
  return g_object_new (ECV_TYPE_VI_IMAGE,
		       "width", width,
		       "height", height,
		       "bpp", bpp,
		       "file", file,
		       NULL);
}
